
// Copyright (C) Recursion Company. All rights reserved.

#include "stdafx.h"
#include "vol_user_app_info.h"

void CVWnd_RichEdit::OnConstruct ()
{
    m_blPlainTextMode = FALSE;
    m_nContentType = 0;
    m_nBorderType = 1;
    m_clrBackColor = CLR_DEFAULT;
    m_blMutiLine = TRUE;
    m_blAutoNextLine = TRUE;
    m_blReadOnly = FALSE;
    m_blHideSelection = TRUE;
    m_nMaxAllowLength = 0;
    m_nSelStart = 0;
    m_nSelLength = 0;

    m_hInstRichEdit = NULL;
}

BOOL CVWnd_RichEdit::CreateControl (CVolNativeWndCreateParam* pCreateParam)
{
	if (m_hInstRichEdit == NULL)
    {
		m_hInstRichEdit = LoadLibrary (_T ("RICHED20.DLL"));
        if (m_hInstRichEdit == NULL)
            return FALSE;
    }

	if (m_blHideSelection == FALSE)
		pCreateParam->m_dwStyle |= ES_NOHIDESEL;

	if (m_blMutiLine)
	{
		pCreateParam->m_dwStyle |= (ES_MULTILINE | ES_WANTRETURN | ES_AUTOVSCROLL | WS_VSCROLL);

		if (m_blAutoNextLine == FALSE)
			pCreateParam->m_dwStyle |= (ES_AUTOHSCROLL | WS_HSCROLL);
	}
	else
		pCreateParam->m_dwStyle |= ES_AUTOHSCROLL;

	if (m_blReadOnly)
		pCreateParam->m_dwStyle |= ES_READONLY;

    if (CWnd::CreateEx (pCreateParam->m_dwExStyle, RICHEDIT_CLASS, _T (""), pCreateParam->m_dwStyle,
            pCreateParam->m_nLeft, pCreateParam->m_nTop, pCreateParam->m_nWidth, pCreateParam->m_nHeight,
            pCreateParam->m_pParentWnd->GetSafeHwnd (), (HMENU)pCreateParam->m_nID))
	{
    #ifdef EM_SETTEXTMODE
        if (m_blPlainTextMode)
            ::SendMessage (m_hWnd, EM_SETTEXTMODE, (WPARAM)(TM_PLAINTEXT | TM_MULTILEVELUNDO | TM_MULTICODEPAGE), 0);
    #endif

        LOGFONT infFont;
        VERIFY_NOT_EQUAL (::GetObject (::GetStockObject (DEFAULT_GUI_FONT), sizeof (LOGFONT), &infFont), 0);

        CHARFORMAT cf;
        ZERO_MEM (&cf, sizeof (CHARFORMAT));
        cf.cbSize = sizeof (cf);
        cf.dwMask = (CFM_BOLD | CFM_COLOR | CFM_FACE | CFM_ITALIC | CFM_OFFSET |
                CFM_PROTECTED | CFM_SIZE | CFM_STRIKEOUT | CFM_UNDERLINE | CFM_CHARSET);
        _tcscpy (cf.szFaceName, infFont.lfFaceName);
        cf.yHeight = 9 * 20;
        cf.dwEffects = CFE_AUTOCOLOR;
		cf.bCharSet = DEFAULT_CHARSET;
        SetDefaultCharFormat (cf);

        SetContent (pCreateParam->m_szCaption, FALSE);
		LimitRichEditText (m_nMaxAllowLength);
        SetRichEditSel (m_nSelStart, m_nSelLength);

        if (m_clrBackColor == CLR_DEFAULT)
            SetBackgroundColor (TRUE, RGB (255, 255, 255));
        else
            SetBackgroundColor (FALSE, m_clrBackColor);

        SetEventMask (ENM_SELCHANGE | ENM_CHANGE | ENM_SCROLL | ENM_PROTECTED);
        SetOptions (ECOOP_OR, ECO_AUTOWORDSELECTION);
        SetModify (FALSE);

		return TRUE;
	}

    return FALSE;
}

BEGIN_MESSAGE_MAP(CVWnd_RichEdit, CRichEditCtrl)
	//{{AFX_MSG_MAP(CVWnd_RichEdit)
	ON_CONTROL_REFLECT(EN_CHANGE, OnChange)
	ON_CONTROL_REFLECT(EN_KILLFOCUS, OnKillfocus)
	ON_CONTROL_REFLECT(EN_SETFOCUS, OnSetfocus)
	ON_NOTIFY_REFLECT(EN_PROTECTED, OnProtected)
	ON_NOTIFY_REFLECT(EN_SELCHANGE, OnSelChange)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

void CVWnd_RichEdit::OnSetfocus() 
{
    SendSetFocusNativeMessage (m_hWnd, m_pEventListener);
}

void CVWnd_RichEdit::OnKillfocus()
{
	SendKillFocusNativeMessage (m_hWnd, m_pEventListener);
}

void CVWnd_RichEdit::OnChange() 
{
    if (m_pEventListener != NULL)
        m_pEventListener->OnChange ();
}

void CVWnd_RichEdit::OnSelChange(NMHDR* pNMHDR, LRESULT* pResult)
{
    if (m_pEventListener != NULL)
        m_pEventListener->OnSelChange ();
}

void CVWnd_RichEdit::OnProtected(NMHDR* pNMHDR, LRESULT* pResult)
{
	ENPROTECTED* pEnProtected = (ENPROTECTED*)pNMHDR;
	CHARFORMAT* pCharFormat = (CHARFORMAT*) pEnProtected->lParam;

	if (pEnProtected->msg == EM_SETCHARFORMAT)
		*pResult = 0;
	else
		*pResult = 1;
}

static DWORD CALLBACK sEditStreamOutCallback (DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
{
    ((CVolMem*)dwCookie)->Append (pbBuff, cb);
    *pcb = cb;
    return 0;
}

void CVWnd_RichEdit::GetContent (CVolString& strContent, BOOL blOnlySelection)
{
    INT nFormat = (m_nContentType == 0 ? (SF_TEXT | SF_UNICODE) : SF_RTF);
    if (blOnlySelection)
        nFormat |= SFF_SELECTION;

    CVolMem mem;
    EDITSTREAM inf;
    inf.dwCookie = (DWORD_PTR)&mem;
    inf.dwError = 0;
    inf.pfnCallback = sEditStreamOutCallback;

    StreamOut (nFormat, inf);
    mem.AddDWord (0);

    if (m_nContentType == 0)
    {
        strContent.SetText (mem.GetTextPtr ());
    }
    else
    {
        CVolMem memBuf;
        strContent.SetText (GetWideText ((const CHAR*)mem.GetPtr (), memBuf, NULL));
    }
}

static DWORD CALLBACK sEditStreamInCallback (DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
{
    CVolMem* pMem = (CVolMem*)dwCookie;
    if (cb > pMem->GetSize ())
        cb = (LONG)pMem->GetSize ();
    if (cb > 0)
    {
        COPY_MEM (pbBuff, pMem->GetPtr (), cb);
        pMem->Remove (0, cb);
    }
    *pcb = cb;
    return 0;
}

void CVWnd_RichEdit::SetContent (LPCTSTR szContent, BOOL blOnlySelection)
{
    INT nFormat = (m_nContentType == 0 ? (SF_TEXT | SF_UNICODE) : SF_RTF);
    if (blOnlySelection)
        nFormat |= SFF_SELECTION;

    CVolMem mem;
    if (m_nContentType == 0)
    {
        mem.AddOnlyText (szContent);
    }
    else
    {
        CVolMem memBuf;
        INT_P npTextLength;
        const CHAR* ps = GetMbsText (szContent, memBuf, &npTextLength);

        mem.Append (ps, npTextLength * sizeof (CHAR));
    }

    EDITSTREAM inf;
    inf.dwCookie = (DWORD_PTR)&mem;
    inf.dwError = 0;
    inf.pfnCallback = sEditStreamInCallback;

    StreamIn (nFormat, inf);
}

void CVWnd_RichEdit::SetRichEditSel (INT nSelStart, INT nSelLength)
{
    nSelStart = MAX (0, nSelStart);

    if (nSelLength < 0)
        SetSel (0, -1);
    else
		SetSel (nSelStart, nSelStart + nSelLength);
}
